﻿using Ace.Application;
using Ace.Attributes;
using Ace.Exceptions;
using Ace.Web.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Ace;
using System.Reflection;
using System.Security.Claims;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication;
using Chloe.Ext.Intf;
using Chloe.Ext;
using Ace.Application;
using Newtonsoft.Json.Linq;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using System.Text;
using Microsoft.Extensions.Caching.Distributed;
using Newtonsoft.Json;
using System.IO;
using log4net;

namespace Ace.Web.Mvc.Common
{
    public abstract class CsHttpController : BaseController
    {
        private const string privateCookieName = "pmyCookie";
        public static string virtualPath;
        private static int ct_ConnCount;
        private static int ct_ConnTimeout;
        private JsonSerializerSettings jsonsetting;
        private int cookieExpireSeconds = 1800;
        protected readonly IDistributedCache _distributedCache;
        public static Assembly logrepositoryname { get { return Assembly.GetEntryAssembly(); } }
      public   static string strname = string.Format("{0}.{1}.{2}", "runInfo",
                    MethodBase.GetCurrentMethod().DeclaringType,
                    MethodBase.GetCurrentMethod().Name);
        /// <summary>
        /// 记录系统运行状况的日志,通常使用error和fatal级别
        /// </summary>
        public  ILog runLoger = LogManager.GetLogger(logrepositoryname, strname);
        /// <summary>
        /// 设置本地cookie
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="value">值</param>  
        /// <param name="secs">过期时长，单位：秒</param>      
        protected void SetCookies(string key, string value, int secs = 30)
        {
            HttpContext.Response.Cookies.Append(key, value, new CookieOptions
            {
                Expires = DateTime.Now.AddSeconds(secs)
            });
        }
        /// <summary>
        /// 根据请求头中的vcCodeID获取
        /// </summary>
        public string VerifyCodeKey
        {
            get
            {
                if (this.Request.Headers.ContainsKey("vcCodeID"))
                {
                    var code = this.Request.Headers["vcCodeID"];
                    FrmLib.Log.commLoger.devLoger.DebugFormat("vcodeis:{0}", code);
                    return code;
                }
                else
                {

                    string vcid = Guid.NewGuid().ToString();
                    FrmLib.Log.commLoger.devLoger.DebugFormat("vccode not contain,create new {0}", vcid);
                    //this.Response.Cookies.Append("vcCodeID",vcid);
                    return vcid;


                }

            }
        }
        /// <summary>
        /// 删除指定的cookie
        /// </summary>
        /// <param name="key">键</param>
        protected void DeleteCookies(string key)
        {
            HttpContext.Response.Cookies.Delete(key);
        }

        /// <summary>
        /// 获取cookies
        /// </summary>
        /// <param name="key">键</param>
        /// <returns>返回对应的值</returns>
        protected string GetCookies(string key)
        {
            HttpContext.Request.Cookies.TryGetValue(key, out string value);
            if (string.IsNullOrEmpty(value))
                value = string.Empty;
            return value;
        }
        protected string getJsonFromBody()
        {
            StreamReader reader = new StreamReader(this.Request.Body);
            string str = reader.ReadToEnd();
            return str;
        }
        protected string ModelStateErrors(ModelStateDictionary ModelState)
        {
            StringBuilder sb = new StringBuilder();
            var errorFieldsAndMsgs = ModelState.Where(m => m.Value.Errors.Any())
                          .Select(x => new { x.Key, x.Value.Errors });
            foreach (var item in errorFieldsAndMsgs)
            {

                //获取键
                var fieldKey = item.Key;
                //获取键对应的错误信息
                foreach (var fieldErrors in item.Errors)
                {
                    string msg = fieldErrors.Exception == null ? fieldErrors.ErrorMessage : fieldErrors.Exception.Message;
                    sb.Append(fieldKey + ":" + msg + Environment.NewLine);
                }



            }
            return sb.ToString();
        }
        public CsHttpController(IDistributedCache distributedCache)
        {
            this._distributedCache = distributedCache;
            Newtonsoft.Json.JsonSerializerSettings setting = new Newtonsoft.Json.JsonSerializerSettings();
            JsonConvert.DefaultSettings = new Func<JsonSerializerSettings>(() =>
            {
                //日期类型默认格式化处理  
                setting.DateFormatHandling = Newtonsoft.Json.DateFormatHandling.MicrosoftDateFormat;
                setting.DateFormatString = "yyyy-MM-dd HH:mm:ss";
                //setting.ContractResolver = new JsonPropertiesResolver();

                //空值处理  
                //setting.NullValueHandling = NullValueHandling.Ignore;

                //高级用法九中的Bool类型转换 设置  
                //  setting.Converters.Add(new BoolConvert("是,否"));

                return setting;
            });

        }
        private IContextSpace _objectSpace;
        protected IContextSpace objectSpace
        {
            get
            {

                if (_objectSpace == null)
                {
                    var csService = AppServicesFactory.CreateService<IObjectSpaceService>();

                    _objectSpace = csService.getContextSpace();

                }
                return _objectSpace;
            }
        }
        /// <summary>
        /// C#将IP地址转为长整形
        /// </summary>
        /// <param name="ip"></param>
        /// <returns></returns>
        private long IpToNumber(string ip)
        {
            string[] arr = ip.Split('.');
            return 256 * 256 * 256 * long.Parse(arr[0]) + 256 * 256 * long.Parse(arr[1]) + 256 * long.Parse(arr[2]) + long.Parse(arr[3]);
        }
        /// <summary>
        /// C#判断IP地址是否为私有/内网ip地址
        /// </summary>
        /// <param name="ip"></param>
        /// <returns></returns>
        private bool IsPrivateIp(string ip)
        {
            long ABegin = IpToNumber("10.0.0.0"), AEnd = IpToNumber("10.255.255.255"),//A类私有IP地址
             BBegin = IpToNumber("172.16.0.0"), BEnd = IpToNumber("172.31.255.255"),//'B类私有IP地址
             CBegin = IpToNumber("192.168.0.0"), CEnd = IpToNumber("192.168.255.255"),//'C类私有IP地址
             IpNum = IpToNumber(ip);
            return (ABegin <= IpNum && IpNum <= AEnd) || (BBegin <= IpNum && IpNum <= BEnd) || (CBegin <= IpNum && IpNum <= CEnd);
        }
        public string remoteIP
        {
            get
            {
                string ip = this.Request.Headers["X-Forwarded-For"];
                if (string.IsNullOrEmpty(ip))
                    ip = Request.HttpContext.Connection.RemoteIpAddress.ToString();
                else//代理ip地址有内容，判断是否符合ipv4地址或者是否为内网地址
                {
                    ip = ip.Trim().Replace(" ", "");
                    if (!System.Text.RegularExpressions.Regex.IsMatch(ip, @"^\d+(\.\d+){3}$")
                        || IsPrivateIp(ip))
                        ip = Request.HttpContext.Connection.RemoteIpAddress.ToString();//不符合规则或者内网/私有地址使用remote_addr代替
                }
                return ip;

            }
        }
        /*
        public override ContentResult JsonContent(object obj)
        {
            string json;
            IJsonSerialize jobj = obj as IJsonSerialize;
            if (jobj != null)
            {
                json = jobj.toJsonString();
                return base.Content(json);
            }
            else
               return  base.JsonContent(obj);
            
           
            
        }
        */
        protected int PageNumber
        {
            get
            {
                int pn = 1;
                if (this.Request.Headers.ContainsKey("PageNumber"))
                {
                    string str = Request.Headers["PageNumber"].First<string>();
                    if (!int.TryParse(str, out pn))
                        pn = 1;
                    if (pn < 1)
                        pn = 1;
                }
                return pn;
            }
        }
        protected int CountPerPage
        {
            get
            {
                int cpp = 100;
                if (Request.Headers.Keys.Contains("CountPerPage"))
                {
                    string str = Request.Headers["CountPerPage"].First<string>();
                    if (!int.TryParse(str, out cpp))
                        cpp = 10;
                    if (cpp < 1)
                        cpp = 100;
                }
                return cpp;
            }
        }
        protected string baseUrl
        {
            get
            {
                string baseurl = Request.Protocol + "://" + Request.Host;
                if (virtualPath.Last() != '/')
                    virtualPath = virtualPath + "/";
                return (baseurl + virtualPath).Replace("//", "/");
            }
        }
        protected string PhoneOS
        {
            get
            {
                string str = "other";
                if (this.Request.Headers.Keys.Contains("PhoneOS"))
                {
                    str = Request.Headers["PhoneOS"].First<string>();

                }
                return str;
            }
        }

        public void Commit(bool useTransaction = true)
        {
            this.objectSpace.UpdateAllDirtyObjects(useTransaction);
        }



        protected override void Dispose(bool disposing)
        {

            var csService = AppServicesFactory.CreateService<IObjectSpaceService>();

            if (_objectSpace == null)
                csService.returnContextSpace(this.objectSpace);
            this._objectSpace = null;
            base.Dispose(disposing);
        }


        protected void UpdateDatabase(bool useTransaction = true)
        {

            this.objectSpace.UpdateAllDirtyObjects(useTransaction);
        }





        protected Boolean isweixin()
        {
            string userAgent = Request.Headers["User-Agent"].First<string>();
            if (userAgent.ToLower().Contains("micromessenger"))
            {
                return true;
            }
            else
            {
                return false;
            }

        }
        [Disposable]
        AppServiceFactory _appServicesFactory;
       protected IAppServiceFactory AppServicesFactory
        {
            get
            {
                if (this._appServicesFactory == null)
                    this._appServicesFactory = new AppServiceFactory(this.HttpContext.RequestServices, this.CurrentSession);
                return this._appServicesFactory;
            }
        }

        [NonAction]
        public override void OnActionExecuted(ActionExecutedContext context)
        {
            System.Threading.Thread.CurrentPrincipal = null;
        }
        [NonAction]
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            if (filterContext.HttpContext.User == null || filterContext.HttpContext.User.Identity == null)
            {
                filterContext.Result = this.FailedMsg("用户授权有异常");
            }
            if (System.Threading.Thread.CurrentPrincipal == null)
            {
                ClaimsIdentity ci = filterContext.HttpContext.User.Identity as ClaimsIdentity;
                var userPrincipal = new ClaimsPrincipal(ci);
                System.Threading.Thread.CurrentPrincipal = userPrincipal;
            }
            ObsoleteApiAttribute obsoleteAttr = filterContext.ActionDescriptor.FilterDescriptors.Where(a => a.Filter is ObsoleteApiAttribute).Select(a => a.Filter).FirstOrDefault() as ObsoleteApiAttribute;

            if (obsoleteAttr == null)
            {
                obsoleteAttr = filterContext.Controller.GetType().GetCustomAttributes<ObsoleteApiAttribute>().FirstOrDefault() as ObsoleteApiAttribute;
            }

            if (obsoleteAttr != null)
            {
                filterContext.Result = this.FailedMsg(obsoleteAttr.Message);
            }

            base.OnActionExecuting(filterContext);
        }

        AdminSession _session;
        public AdminSession CurrentSession
        {
            get
            {
                
                if (this._session != null)
                    return this._session;
                
                if (this.HttpContext.User.Identity.IsAuthenticated == false)

                {
                    
                    return null;
                }
                AdminSession session = AdminSession.Parse(this.HttpContext.User);
                this._session = session;
                return session;
            }
            set
            {
                AdminSession session = value;

                if (session == null)
                {
                    //注销登录
                    this.HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
                    this.DeleteCookies(privateCookieName);
                    System.Threading.Thread.CurrentPrincipal = null;
                    return;
                }

                List<Claim> claims = session.ToClaims();
                var expirestr = Globals.Configuration["Cookie:ExpireSeconds"];
                if (!string.IsNullOrEmpty(expirestr))
                    cookieExpireSeconds = int.Parse(expirestr);
                session.expTime = DateTime.Now.AddSeconds(cookieExpireSeconds);
                //init the identity instances 
                var userPrincipal = new ClaimsPrincipal(new ClaimsIdentity(claims, 
                    CookieAuthenticationDefaults.AuthenticationScheme));
                this.HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, 
                    userPrincipal, new AuthenticationProperties
                {
                    ExpiresUtc = DateTime.UtcNow.AddSeconds(cookieExpireSeconds),
                    IsPersistent = true,
                    AllowRefresh = false
                });
                var clv = (from x in claims where x.Type == "UserId" select x).FirstOrDefault();
                var userid = (clv == null ? "-1" : clv.Value);
                var jobj = Newtonsoft.Json.Linq.JObject.FromObject(new { uid = userid, sid = session.sessionID });
                SetCookies(privateCookieName, jobj.ToString(), cookieExpireSeconds);
                System.Threading.Thread.CurrentPrincipal = userPrincipal;
                //IAuthenticationService authenticationService = this.HttpContext.RequestServices.GetService(typeof(IAuthenticationService)) as IAuthenticationService;
                //authenticationService.SignInAsync(this.HttpContext, CookieAuthenticationDefaults.AuthenticationScheme, userPrincipal, new AuthenticationProperties
                //{
                //    ExpiresUtc = DateTime.UtcNow.AddMinutes(60),
                //    IsPersistent = false,
                //    AllowRefresh = false
                //});

                if (this._appServicesFactory != null)
                {
                    this._appServicesFactory.Session = session;
                }

                this._session = session;
            }
        }

        protected T CreateService<T>() where T : IAppService
        {
            return this.AppServicesFactory.CreateService<T>();
        }
    }
}